package
{
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.events.TouchEvent;
	import flash.geom.Point;
	import flash.ui.Multitouch;
	import flash.ui.MultitouchInputMode;
	import flash.utils.Timer;

	/**
	 * ...
	 * @author PH
	 */
	public class RotatableScalable extends Sprite
	{
		protected var _stage:Stage;
		protected var GRAD_PI:Number = 180.0 / 3.14159;
		protected var touchPos:Array = new Array();
		protected var touchID:Array = new Array();
		public var allowDrag:Boolean = true;
		public var allowRotate:Boolean = true;
		protected var touchMark:String;
		protected const DRAG:String = 'drag';
		protected const ZOOM_ROTATE:String = 'zoom_rotate';
		protected var resetFirstPoi:Boolean;
		protected var resetSecondPoi:Boolean;
		protected var temScale:Number = 1;
		protected var temRotate:Number = 0;
		protected var _sizeMax:Number = 7000;
		protected var _sizeMin:Number = 200;
		public var time:uint = 200;
		public var scope:uint = 10;
		public static const DOUBLE_CLICK:String = "double_click";
		protected var clickTimer:Timer = new Timer(1000);
		protected var clickPos:Point;
		
		
		
		public function RotatableScalable(getStage:Stage):void {
			_stage = getStage;
			
			clickTimer = new Timer(time);
            clickTimer.addEventListener(TimerEvent.TIMER, timerHandler);
			scope *= 2;
			_stage.addEventListener(MouseEvent.CLICK, clickHandler);
			
			
			if (Multitouch.supportsGestureEvents) {
				Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
				
				this.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
				_stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
				_stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
			}
			
			addEventListener(Event.REMOVED_FROM_STAGE, clears);
		}
		
		private function clears(e:Event):void 
		{
			removeEventListener(Event.REMOVED_FROM_STAGE, clears);
			TouchControler(false);
		}
		
		public function TouchControler(b:Boolean):void
		{
			if (b) {
				_stage.addEventListener(MouseEvent.CLICK, clickHandler);
				addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
				_stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd);
				_stage.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
			}else {
				_stage.removeEventListener(MouseEvent.CLICK, clickHandler);
				removeEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin);
				//_stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEnd);
				_stage.removeEventListener(TouchEvent.TOUCH_MOVE, onTouchMove);
			}
		}
		
		protected function clickHandler(e:MouseEvent):void 
		{
			if (clickTimer.running)	
			{
				if (Math.abs(e.stageX - clickPos.x) < scope && Math.abs(e.stageY - clickPos.y) < scope)
				{
					_stage.dispatchEvent(new Event(DOUBLE_CLICK));
					clickTimer.stop();
				}
			}
			else {
				clickPos = new Point(e.stageX, e.stageY);
				
				clickTimer.start();
			}
            
		}
		protected function timerHandler(e:Event):void 
		{
			clickTimer.stop();
		}
		
		protected function onTouchBegin(e:TouchEvent):void
		{
			touchID.push(e.touchPointID);
			touchPos.push([new Point(e.localX, e.localY), new Point(e.stageX, e.stageY), new Point()]);
			
			if (touchID.length == 1)
			{
				touchMark = DRAG;
			}
			else if (touchID.length == 2)
			{
				touchMark = ZOOM_ROTATE;
				resetFirstPoi = true;
			}
			else
			{
				trace(touchID.length);
				trace('不支持两点以上操作');
			}
			
		}
		
		protected function onTouchMove(e:TouchEvent):void {
			for (var i:Object in touchID)
			{
				if (touchID[i] == e.touchPointID)
				{
					touchPos[i][2].x = e.stageX;
					touchPos[i][2].y = e.stageY;
					
					if (resetFirstPoi && i == 0)
					{
						touchPos[0][1].x = e.stageX;
						touchPos[0][1].y = e.stageY;
						
						temScale = this.scaleX;
						temRotate = this.rotation;
						
						resetFirstPoi = false;
					}
					
					if (resetSecondPoi)
					{
						touchPos[0][1].x = e.stageX;
						touchPos[0][1].y = e.stageY;
						touchPos[0][0] = this.globalToLocal(touchPos[0][1]);
						
						resetSecondPoi = false;
					}
					
					if (touchMark == DRAG && allowDrag) 
					{
						updatePositon();
					}
					else if (touchMark == ZOOM_ROTATE && i == 1)
					{
						var L1:Number = Math.sqrt(Math.pow(touchPos[0][1].x - touchPos[1][1].x, 2) + Math.pow(touchPos[0][1].y - touchPos[1][1].y, 2));
						var L2:Number = Math.sqrt(Math.pow(touchPos[0][2].x - touchPos[1][2].x, 2) + Math.pow(touchPos[0][2].y - touchPos[1][2].y, 2));
						var currentScale:Number = temScale * (L2 / L1);
						this.scaleX = this.scaleY = currentScale;
						
						if (this.width > this.height)
						{
							if (this.height < _sizeMin) 
							{
								this.height = _sizeMin;
								this.scaleX = this.scaleY;
							}
							else if (this.width > _sizeMax)
							{
								this.width = _sizeMax;
								this.scaleY = this.scaleX;
							}
						}
						else
						{
							if (this.width < _sizeMin)
							{
								this.width = _sizeMin;
								this.scaleY = this.scaleX;
							}
							else if (this.height > _sizeMax)
							{
								this.height = _sizeMax;
								this.scaleX = this.scaleY;
							}
						}
						
						if (allowRotate)
						{
							var angle1:Number = getAngleTrig(touchPos[0][1].x - touchPos[1][1].x, touchPos[0][1].y - touchPos[1][1].y);
							var angle2:Number = getAngleTrig(touchPos[0][2].x - touchPos[1][2].x, touchPos[0][2].y - touchPos[1][2].y);
							var currentRotate:Number = temRotate + (angle2 - angle1);
							this.rotation = currentRotate;
						}
						
						updatePositon();
					}
					
				}
			}
			
		}
		protected function onTouchEnd(e:TouchEvent):void {
			for (var i:* in touchID) 
			{
				if (touchID[i] == e.touchPointID)
				{
					touchID.splice(i, 1);
					touchPos.splice(i, 1);
					
					if (touchID.length == 1 && this.hitTestPoint(touchPos[0][2].x, touchPos[0][2].y))
					{
						touchMark = DRAG;
						resetSecondPoi = true;
					}
					
					else if (touchID.length == 0)
					{
						touchMark = null;
					}
					
				}
			}
			
		}
		
		protected function updatePositon():void {
			var temP:Point = this.localToGlobal(touchPos[0][0]);
			this.x += touchPos[0][2].x - temP.x;
			this.y += touchPos[0][2].y - temP.y;
		}
		protected function getAngleTrig(X:Number, Y:Number): Number {
			if (X == 0)
			{
				if(Y < 0)
					return 270;
				else
					return 90;
			}
			else if (Y == 0)
			{
				if(X < 0)
					return 180;
				else
					return 0;
			}
			
			if (Y > 0)
			{
				if (X > 0)
					return Math.atan(Y / X) * GRAD_PI;
				else
					return 180 - Math.atan(Y / -X) * GRAD_PI;
			}
			else
			{
				if (X > 0)
					return 360 - Math.atan( -Y / X) * GRAD_PI;
				else
					return 180 + Math.atan( -Y / -X) * GRAD_PI;
			}
		}
		public function set sizeMax(value:Number):void 
		{
			if (value < 7000) _sizeMax = value;
		}
		public function set sizeMin(value:Number):void 
		{
			if (value > 200) _sizeMin = value;
		}
		
	}

}